using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace DiskSpace
{
    public delegate void DiskClickEventHandler(object sender, DiskClickEventArgs e);

    public partial class DiskInfo : UserControl
    {
        private static string[] m_sizeText = { "B", "kB", "MB", "GB", "TB" };
        private bool m_labelVisible = true;

        private bool m_showLabels = true;
        private Int32 m_warningThreshold = 75;
        private Int32 m_alarmThreshold = 95;
        private Int64 m_sizeVal = 0;
        private Int64 m_space = 0;
        private Int32 m_percentVal;
        
        /// <summary>
        /// 
        /// </summary>
        public DiskInfo()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 
        /// </summary>
        public string Label
        {
            get
            {
                return this.m_label.Text;
            }
            set
            {
                this.m_label.Text = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public string Disk
        {
            get
            {
                return this.m_disk.Text;
            }
            set
            {
                this.m_disk.Text = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public Int32 WarningThreshold
        {
            set { m_warningThreshold = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public Int32 AlarmThreshold
        {
            set { m_alarmThreshold = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public Int64 DiskSize
        {
            get
            {
                return m_sizeVal;
            }
            set
            {
                m_sizeVal = value;
                this.m_size.Text = DisplaySizeUsage(m_space, m_sizeVal);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public Int64 Space
        {
            get
            {
                return m_space;
            }
            set
            {
                m_space = value;
                UpdatePercentDisplay();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private void UpdatePercentDisplay()
        {
            m_percentVal = Convert.ToInt32((m_sizeVal > 0) ? 100 - (m_space * 100 / m_sizeVal) : 0);
            m_percent.Text = Convert.ToString(m_percentVal) + "%";
            if (m_percentVal > m_alarmThreshold)
            {
                m_percent.ForeColor = Color.Red;
            }
            else if (m_percentVal > m_warningThreshold)
            {
                m_percent.ForeColor = Color.OrangeRed;
            }
            else
            {
                m_percent.ForeColor = Color.Green;
            }
            m_percentBar.Value = m_percentVal;
            this.m_size.Text = DisplaySizeUsage(m_space, m_sizeVal);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="used"></param>
        /// <param name="total"></param>
        /// <returns></returns>
        private string DisplaySizeUsage(Int64 used, Int64 total)
        {
            int units;
            int divider = CalculateDivider(total,out units);

            return SizeToString(used, divider) + "/" + SizeToString(total, divider) + m_sizeText[units];
        }

        /// <summary>
        /// This method calculates what the divider should be to get the supplied number to a manageable display size. It
        /// also counts how many divides it takes to achieve this.
        /// </summary>
        /// <param name="size">Size to calculate the parameters for</param>
        /// <param name="count">Output parameter of how many divides it took to divide down the supplied size</param>
        /// <returns></returns>
        private int CalculateDivider(Int64 size, out int count)
        {
            int divider = 1;
            Int64 tmpTotal = size;
            count = 0;

            while (tmpTotal > 1024)
            {
                count++;
                divider *= 1024;
                tmpTotal /= 1024;
            }


            return divider;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="size"></param>
        /// <param name="divider"></param>
        /// <returns></returns>
        private string SizeToString(Int64 size, int divider)
        {
            string[] sizeText = { "B", "KB", "MB", "GB", "TB", "PB"};

            String sizeTextVal;

            if (size / divider < 10)
            {
                float decSize = (float)size / divider;
                sizeTextVal = decSize.ToString("F2");
            }
            else
            {
                size /= divider;
                sizeTextVal = size.ToString();
            }

            return sizeTextVal;
        }

        //////////////////////////////////////////////////////////////////////////////////////
        // Event Handling
        //////////////////////////////////////////////////////////////////////////////////////
        public event DiskClickEventHandler DiskClick;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnDiskClick(DiskClickEventArgs e)
        {
            if (DiskClick != null)
            {
                DiskClick(this, e);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private void OnClickHandler()
        {
            DiskClickEventArgs ev = new DiskClickEventArgs();
            ev.DiskName = this.m_disk.Text;
            OnDiskClick(ev);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void InfoClick(object sender, MouseEventArgs e)
        {
            switch(e.Button)
            {
                case System.Windows.Forms.MouseButtons.Left:
                    OnClickHandler();
                    break;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool ShowLabels
        {
            set
            {
                m_showLabels = value;

                if (m_showLabels == false && m_labelVisible == true)
                {
                    m_labelVisible = false;
                    m_label.Visible = false;
                    m_panel.Width += m_label.Width;
                }

                if (m_showLabels == true && m_labelVisible == false)
                {
                    m_labelVisible = true;
                    m_label.Visible = true;
                    m_panel.Width -= m_label.Width;
                }
            }
        }
    }
}
